package pl.edu.pw.polygen.servlet;

import java.io.IOException;
import java.util.Locale;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;

import com.vaadin.Application;
import com.vaadin.terminal.gwt.server.AbstractApplicationServlet;

public class WebApplicationServlet extends AbstractApplicationServlet {

	/**
	 * serialVersionUID
	 */
	private static final long serialVersionUID = 2229816979183469746L;

	private static final Log LOG = LogFactory.getLog(WebApplicationServlet.class);

	/**
	 * The Application Class installed on servlet.
	 */
	private Class<? extends Application> applicationClass;
	private LocaleResolver localeResolver;

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void init(ServletConfig servletConfig) throws ServletException {
		super.init(servletConfig);
		WebApplicationContext applicationContext = getContext();
		this.applicationClass = applicationContext.getBean(Application.class).getClass();
		try {
			this.localeResolver = (LocaleResolver) applicationContext.getBean(DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
		} catch (NoSuchBeanDefinitionException ex) {
			this.localeResolver = new SessionLocaleResolver();
		}
		LOG.info(String.format("Servlet initialized with application class: %s", this.applicationClass.getName()));
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		final Locale locale = localeResolver.resolveLocale(request);
		LocaleContextHolder.setLocale(locale);
		ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request);
		RequestContextHolder.setRequestAttributes(requestAttributes);
		try {
			super.service(new HttpServletRequestWrapper(request) {
				@Override
				public Locale getLocale() {
					return locale;
				}
			}, response);
		} finally {
			if (!locale.equals(LocaleContextHolder.getLocale())) {
				localeResolver.setLocale(request, response, LocaleContextHolder.getLocale());
			}
			LocaleContextHolder.resetLocaleContext();
			RequestContextHolder.resetRequestAttributes();
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected Application getNewApplication(HttpServletRequest request) throws ServletException {
		return getContext().getBean(Application.class);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected Class<? extends Application> getApplicationClass() throws ClassNotFoundException {
		return this.applicationClass;
	}

	/**
	 * Find the root WebApplicationContext for this web application.
	 * 
	 * @return the root WebApplicationContext for this web app
	 */
	private WebApplicationContext getContext() {
		return WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
	}

}
